import sys
import os
import re
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QDir, QFileSystemWatcher,QUrl,QTimer
# from PyQt5.QtGui import QFileSystemModel
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.Qsci import QsciScintilla, QsciLexerCustom
from PyQt5.QtGui import QColor, QFont


from docutils.core import publish_string

# from mod_highlight import RSTHighlighter
from mod_highlight_rst import RstLexer
from mod_test import RstTest

EDIT_MODE = 0
PREVIEW_MODE = 1

class RSTEditor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.current_dir = QDir.currentPath()  # 初始化当前目录
        self.mathjax_dir = "Mathjax " + self.current_dir + '/third_party/mathjax/es5/tex-chtml-full.js'
        self.file_watcher = QFileSystemWatcher()  # 文件监视器
        self.update_toc_timer = QTimer()
        self.update_toc_timer.setSingleShot(True)
        self.update_toc_timer.timeout.connect(self.update_toc_tree)

        self.init_ui()
        self.setWindowTitle("MD和RST文本编辑器")
        self.setGeometry(100, 100, 1600, 900)
        self.init_highlighter()

    def init_highlighter(self):
        """初始化语法高亮"""
        pass
        # self.highlighter = RSTHighlighter(self.editor.document())

    def init_ui(self):
        self.baseurl = QUrl.fromLocalFile(os.path.dirname(os.path.abspath(__file__)) + '/')
        # 创建主容器
        main_widget = QWidget()
        main_layout = QHBoxLayout(main_widget)

        # 左侧边栏容器
        self.sidebar_stack = QStackedWidget()
        self.init_sidebar()
        main_layout.addWidget(self.sidebar_stack, stretch=1)

        
        # # 左侧边栏文件树
        # self.sidebar = self.create_sidebar()
        # main_layout.addWidget(self.sidebar, stretch=1)

        # 右侧主编辑区
        self.splitter  = QSplitter(Qt.Horizontal)
        self.editor = QsciScintilla()
        # self.editor.setFontFamily("Consolas")
        # self.editor.setFontPointSize(12)

       # 设置字体
        font = QFont()
        font.setFamily("Songti SC")
        font.setFixedPitch(True)
        font.setPointSize(12)
        self.editor.setFont(font)

        # 设置语法高亮
        self.lexer = RstLexer(self.editor)
        self.editor.setLexer(self.lexer)


        self.editor.textChanged.connect(self.update_preview)
        self.editor.textChanged.connect(self.schedule_toc_update)

        self.preview = QWebEngineView()
        
        self.splitter.addWidget(self.editor)
        self.splitter.addWidget(self.preview)
        self.splitter.setSizes([600, 400])

        main_layout.addWidget(self.splitter, stretch=4)
        
        self.setCentralWidget(main_widget)
        
        # 初始化菜单栏和工具栏
        self.init_menu()

        # 添加快捷键（新增部分）
        self.add_shortcuts()
        self.edit_mode = EDIT_MODE



        rst_content = RstTest.get_test()

        # 初始示例内容
        # self.editor.setPlainText(rst_content)
        self.editor.setText(rst_content)
        
        # 初始化文件监视
        self.file_watcher.directoryChanged.connect(self.update_file_tree)

    def init_sidebar(self):
        """初始化侧边栏视图"""
        # 文件树视图
        self.file_tree = self.create_file_tree()
        
        # 大纲视图
        self.toc_tree = QTreeWidget()
        self.toc_tree.header().hide()
        self.toc_tree.itemClicked.connect(self.jump_to_position)
        
        # 添加到堆叠容器
        self.sidebar_stack.addWidget(self.file_tree)
        self.sidebar_stack.addWidget(self.toc_tree)
        
        # 默认显示文件树
        self.sidebar_stack.setCurrentIndex(0)

    def toggle_sidebar_view(self):
        """切换侧边栏视图"""
        current = self.sidebar_stack.currentIndex()
        new_index = 1 if current == 0 else 0
        self.sidebar_stack.setCurrentIndex(new_index)


    def schedule_toc_update(self):
        """防抖更新大纲"""
        self.update_toc_timer.start(1000)

    def update_toc_tree(self):
        """解析并更新大纲树"""
        self.toc_tree.clear()
        # text = self.editor.toPlainText()
        text = self.editor.text()
        lines = text.split('\n')
        prev_level = 0
        parent_stack = [self.toc_tree.invisibleRootItem()]
        
        for line_num, line in enumerate(lines):
            if self.is_title_line(line, lines, line_num):
                title, level = self.parse_title(line, lines, line_num)
                item = QTreeWidgetItem([title])
                item.line = line_num  # 存储行号
                
                # 调整层级关系
                while level <= prev_level:
                    parent_stack.pop()
                    prev_level -= 1
                
                parent_stack[-1].addChild(item)
                parent_stack.append(item)
                prev_level = level

    def is_title_line(self, line, lines, line_num):
        """判断是否为标题行"""
        if line_num == 0:
            return False
        return (len(line.strip()) > 0 and 
               len(lines[line_num-1].strip()) > 0 and
               re.match(r'^[=\-~^+]+$', line.strip()))

    def parse_title(self, line, lines, line_num):
        """解析标题级别和内容"""
        title_char = line.strip()[0]
        title_text = lines[line_num-1].strip()
        level = self.get_title_level(title_char)
        return title_text, level

    def get_title_level(self, char):
        """获取标题级别"""
        levels = {'=': 1, '-': 2, '~': 3, '^': 4, '+': 5}
        return levels.get(char, 1)

    def jump_to_position(self, item):
        """跳转到指定行"""
        cursor = self.editor.textCursor()
        cursor.setPosition(self.editor.document().findBlockByNumber(item.line).position())
        self.editor.setTextCursor(cursor)
        self.editor.setFocus()

    def create_file_tree(self):
        """创建文件系统树"""
        sidebar = QWidget()
        layout = QVBoxLayout(sidebar)
        
        # 文件系统模型
        self.file_model = QFileSystemModel()
        self.file_model.setRootPath("")
        self.file_model.setNameFilters(["*.rst"])
        self.file_model.setNameFilterDisables(False)
        
        # 文件树视图
        self.tree_view = QTreeView()
        self.tree_view.setModel(self.file_model)
        self.tree_view.setRootIndex(self.file_model.index(self.current_dir))
        self.tree_view.doubleClicked.connect(self.open_selected_file)
        self.tree_view.setAnimated(True)
        self.tree_view.setSortingEnabled(True)
        
        # 隐藏不需要的列
        self.tree_view.hideColumn(1)  # 隐藏大小列
        self.tree_view.hideColumn(2)  # 隐藏类型列
        self.tree_view.hideColumn(3)  # 隐藏修改时间列
        
        # 添加路径导航栏
        self.path_label = QLabel("当前目录: " + self.current_dir)
        refresh_btn = QPushButton("刷新")
        refresh_btn.clicked.connect(self.refresh_sidebar)
        
        layout.addWidget(self.path_label)
        layout.addWidget(refresh_btn)
        layout.addWidget(self.tree_view)
        
        return sidebar

    def init_menu(self):
        """初始化菜单栏"""
        menubar = self.menuBar()
        
        # 文件菜单
        file_menu = menubar.addMenu("&文件")
        open_action = QAction("打开文件", self)
        open_action.triggered.connect(self.open_file)
        open_dir_action = QAction("打开目录", self)
        open_dir_action.triggered.connect(self.open_directory)
        save_action = QAction("保存文件", self)
        save_action.triggered.connect(self.save_file)
        file_menu.addActions([open_action, open_dir_action, save_action])

    def refresh_sidebar(self):
        """刷新侧边栏显示"""
        self.tree_view.setRootIndex(self.file_model.index(self.current_dir))

    def update_file_tree(self, path):
        """文件变动时更新侧边栏"""
        self.file_model.refresh()

    def open_selected_file(self, index):
        """双击打开选中的文件"""
        path = self.file_model.filePath(index)
        if os.path.isfile(path) and path.endswith(".rst"):
            self.load_file(path)

    def load_file(self, path):
        """加载文件到编辑器"""
        with open(path, 'r', encoding='utf-8') as f:
            self.editor.setText(f.read())
        self.current_dir = os.path.dirname(path)
        self.update_current_directory()

    def update_current_directory(self):
        """更新当前目录状态"""
        self.path_label.setText("当前目录: " + self.current_dir)
        self.tree_view.setRootIndex(self.file_model.index(self.current_dir))
        # 更新文件监视路径
        if self.file_watcher.directories():
            self.file_watcher.removePaths(self.file_watcher.directories())
        self.file_watcher.addPath(self.current_dir)

    def open_directory(self):
        """打开目录对话框"""
        directory = QFileDialog.getExistingDirectory(
            self, "选择目录", self.current_dir)
        if directory:
            self.current_dir = directory
            self.update_current_directory()

    # 其余原有方法保持不变...
    def open_file(self):
        """打开文件"""
        path, _ = QFileDialog.getOpenFileName(
            self, "打开文件", self.current_dir, "reStructuredText Files (*.rst)")
        if path:
            self.load_file(path)
            self.current_dir = os.path.dirname(path)
            self.update_current_directory()

    def save_file(self):
        """保存文件"""
        path, _ = QFileDialog.getSaveFileName(
            self, "保存文件", self.current_dir, "reStructuredText Files (*.rst)")
        if path:
            with open(path, 'w', encoding='utf-8') as f:
                f.write(self.editor.text())
            self.current_dir = os.path.dirname(path)
            self.update_current_directory()

    # 保持之前的预览更新和快捷键方法...
    def add_shortcuts(self):
        """添加切换快捷键（新增方法）"""
        # 编辑模式切换
        toggle_edit = QAction("Toggle Edit", self)
        toggle_edit.setShortcut("Ctrl+/")
        toggle_edit.triggered.connect(self.toggle_edit_mode)
        self.addAction(toggle_edit)

        toggle_sidebar = QAction("Toggle Sidebar", self)
        toggle_sidebar.setShortcut("Ctrl+'")
        toggle_sidebar.triggered.connect(self.toggle_sidebar_view)
        self.addAction(toggle_sidebar)

    def toggle_edit_mode(self):
        """切换编辑全屏模式（新增方法）"""
        current_sizes = self.splitter.sizes()

        if self.edit_mode == EDIT_MODE :
            if current_sizes[0] != 0:  # 分栏状态
                self.normal_sizes = current_sizes
                self.splitter.setSizes([0, self.splitter.width()])
                self.edit_mode = PREVIEW_MODE 
        elif self.edit_mode == PREVIEW_MODE :
            if current_sizes[1] != 0:  # 分栏状态
                self.normal_sizes = current_sizes
                self.splitter.setSizes([self.splitter.width(), 0])
                self.edit_mode = EDIT_MODE
        else:  # 已处于编辑模式
            self.splitter.setSizes(self.normal_sizes)

    # 以下原有方法保持不变...
    def update_preview(self):

        # self.schedule_toc_update()

        """更新预览内容"""
        rst_text = self.editor.text()
        settings = {
            'math_output': self.mathjax_dir,  # 启用 MathJax 渲染
            'embed_stylesheet': False,   
            'output_encoding': 'unicode',
            'halt_level': 2
        }
        self.baseurl = QUrl.fromLocalFile(self.current_dir + '/')

        # 配置参数（启用 MathJax 并保留原始 LaTeX）
        try:
            html = publish_string(
                rst_text,
                writer_name="html",
                settings_overrides = settings
            )
            self.preview.setHtml(html,baseUrl=self.baseurl)
        except Exception as e:
            self.preview.setHtml(f"<pre style='color:red'>Error: {str(e)}</pre>",baseUrl=self.baseurl)



if __name__ == "__main__":
    app = QApplication(sys.argv)
    editor = RSTEditor()
    editor.show()
    sys.exit(app.exec_())